#ifndef _GOVT_ROOM_HPP_
#define _GOVT_ROOM_HPP_
/*******************************************************************************
 ** Name: room.hpp                                                            **
 ** Description: Basic rooms and connections                                  **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 ** The contents of this file are subject to the terms of the                 **
 ** Common Development and Distribution License, Version 1.0 only             **
 ** (the "License").  You may not use this file except in compliance          **
 ** with the License.                                                         **
 **                                                                           **
 ** You can find a copy of the license in the LICENSE file within             **
 ** this distribution or at $WIKI/display/GOVT/License-software.              **
 ** Software distributed under the License is distributed on an "AS IS"       **
 ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.           **
 ** See the License for the specific language governing permissions           **
 ** and limitations under the License.                                        **
 **                                                                           **
 ** When distributing Covered Code, include this CDDL header in each          **
 ** file and include the License file at $GAME_DIR/LICENSE.                   **
 ** If applicable, add the following below this header, with the indicated    **
 ** fields enclosed by brackets "[]" replaced with your own identifying       **
 ** information: Portions Copyright [yyyy] [name of copyright owner]          **
 **                                                                           **
 ** Copyright (c) 2009-2012  Barry Gian James <gian@gamingods.net>            **
 ** All rights reserved.                                                      **
 ******************************************************************************/

// $Id$
// Last Modified by $Author$
#include <odb/core.hxx>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <vector>
#include "common.hpp"
#include "item.hpp"
#include "character.hpp"

//! @struct RoomType
//! @brief Information about the room type
#pragma db value table("roomtype")
struct RoomType
{
	#pragma db id auto
	entity_t	idroomtype;
	std::string	name;
	char		map_symbol;
};

//! @struct RoomLighting
//! @brief Information containing lighting and bonuses
#pragma db value table("room_lighting")
struct RoomLighting
{
	#pragma db id auto
	entity_t	idlighting;
	std::string	name;
	short		defense_bonus;
	short		visual_increment;
};

// Door _flags
enum class DoorFlag : uint64_t
{
	Locked = 1, Pickable, Trapped, Damageable,
	HasKey, Sentient, Hidden, Unlockable, Smashable,
	Lockable, Closeable, Obvious, Unobtrusive
};

#define DOOR_LOCKED	0x0001
#define DOOR_PICKABLE	0x0002
#define DOOR_TRAPPED	0x0004
#define DOOR_DAMAGABLE	0x0008
#define DOOR_HAS_KEY	0x0010
#define DOOR_SENTIENT	0x0020	// is the door sentient?
#define DOOR_IS_HIDDEN	0x0080
#define DOOR_CAN_UNLOCK	0x0100
#define DOOR_SMASHABLE  0x0400
#define DOOR_LOCKABLE   0x0800
#define DOOR_CLOSEABLE  0x1000
#define DOOR_OBVIOUS	0x2000

//! @class Position
//! @brief Defines cartesian coordinates inside a room. N.B. (0,0) is always mapped
//! to lower left not center.
class Position
{
public:
  Position(ushort x1, ushort y1) { x = x1; y = y1; }

  operator char * () {
	  char buff[8];
	  sprintf(buff,"%i %i", x,y);
	  return buff;
  }

  ushort        X() { return x; }
  void          X(ushort x1) { x = x1; }
  ushort        Y() { return y; }
  void          Y(ushort y1) { y = y1; }
  bool			Within(ushort d,const Position &p);

//private:
  ushort        x, y;
};

//! @class Portal
//! @brief The class defining all exits from a room or area or region
#pragma db object table("portals")
class Portal
{
public:
	SMART_PTR_DECL(Portal);

	Portal();
	Portal(const Portal &);

	// Getters
	const entity_t	ID() const { return _id; }
	const std::string &	Name() const { return _name; }
	const std::string &	Tag() const { return _tag; }
	const std::string &	Desc() const { return _desc; }
	const std::string & Handle() const { return _handle; }
	const entity_t 	Key() const { return _key; }
	const ushort 	UnlockDC() const { return _unlock_dc; }
	const ushort 	DmgSave() const { return _dmg_save; }
	const ushort 	Durability() const { return _durability; }
	const ushort 	DurabilityMax() const { return _durability_max; }
	const bool 		Open() const { return _open; }
	const EnumFlag<DoorFlag> & Flags() const { return _flags; }
	const ushort 	DetectDC() const { return _detect_dc; }
	const entity_t	Room() const { return _idroom; }
	const entity_t	Destination() const { return _idroom_destination; }

	// Setters
	void	Name(const std::string & n) { _name = n; }
	void	Tag(const std::string & t) { _tag = t; }
	void	Desc(const std::string & d) { _desc = d; }
	void	Handle(const std::string & h) { _handle = h; }
	bool 	Locked() { return _flags.has(DoorFlag::Locked); }
	bool 	Lockable() { return _flags.has(DoorFlag::Lockable); }
	bool 	Pickable() { return _flags.has(DoorFlag::Pickable); }
	bool 	Smashable() { return _flags.has(DoorFlag::Smashable); }
	bool	Unlockable() { return _flags.has(DoorFlag::Unlockable); }
	bool	Hidden() { return _flags.has(DoorFlag::Hidden); }
	bool	HasKey() { return _key != 0; }
	bool	CanDamage() { return _flags.has(DoorFlag::Damageable); }
	bool	Sentient() { return _flags.has(DoorFlag::Sentient); }
	void	Key(entity_t e) { _key = e; }
	void	UnlockDC(ushort v) { _unlock_dc = v; }
	void	DmgSave(ushort v) { _dmg_save = v; }
	void	Durability(short v) { _durability += v; }	// can pass neg value
	void	DurabilityMax(ushort v) { _durability_max = v; }
	void 	Open(bool v) { _open = v; }
	void	DetectDC(ushort v) { _detect_dc = v; }
	void	Room(const entity_t r) { _idroom = r; }
	void	Destination(const entity_t d) { _idroom_destination = d; }

	void	AttachDevice(boost::shared_ptr<Device> d) { _devices.push_back(d); }
	void	DetachDevice(entity_t id);
	boost::shared_ptr<Device> GetDevice(std::string &t);

private:
	friend class odb::access;
	#pragma db id auto
	entity_t	_id;
	std::string	_name;
	std::string	_tag;
	std::string	_desc;
	std::string _handle;
//	unsigned int _flags;
	EnumFlag<DoorFlag> _flags;
	entity_t	_key;
	entity_t	_idroom;
	entity_t	_idroom_destination;
	ushort		_unlock_dc;
	ushort		_detect_dc;	// if hidden
	ushort		_dmg_save;
	ushort		_durability;
	ushort		_durability_max;
	bool		_open;
	bool		_is_barrier;
	std::vector<boost::shared_ptr<Device> > _devices;
};

//! @class VirtualRoomObject
//! @brief Lightweight objects with superficial interactivity
#pragma db value
struct VirtualRoomObject
{
	VirtualRoomObject() { }
	VirtualRoomObject(const std::string &i, const std::string &rt, const std::string & rw) {
		item = i; responds_to = rt; responds_with = rw;
	}
	std::string	item;			// the virtual item name eg "big rock"
	std::string	responds_to;	// the installed interactivity eg "sit"
	std::string responds_with;	// how it responds eg " on a jagged rock"
};

#define ROOM_PVP_ENA		0x01
#define ROOM_HAS_CONTENTS	0x02
#define ROOM_IS_SILENT		0x04
#define ROOM_NO_MAGICK		0x08
#define ROOM_SAFE		0x10

//! @class Room
//! @brief The basic room class
#pragma db object table("rooms")
class Room
{
public:
	SMART_PTR_DECL(Room);

	Room();
	Room(const Room &);

	// Getters
	const entity_t		ID() const { return _id; }
	const entity_t		Region() const { return _idregion; }
	const std::string &	Name() const { return _name; }
	const std::string &	Tag() const { return _tag; }
	const std::string &	Desc() const { return _desc; }
	const boost::posix_time::ptime	LastReset() const { return _last_reset; }
	const RoomType &	Type() const { return _idroom_type; }
	const unsigned int	Flags() const { return _flags; }
	const ushort	Width() const { return _width; }
	const ushort	Length() const { return _length; }
	const RoomLighting	Lighting() const { return _idlighting; }
	const entity_t		Creator() const { return _creator; }
	const std::vector<Character::pointer > & Characters() const { return _chars; }
	const std::vector<boost::shared_ptr<Item> > & Items() const { return _items; }
	const std::vector<Portal::pointer > & GetPortals() const { return _exits; }


	// Setters
	void	Region(entity_t e) { _idregion = e; }
	void	Name(const std::string & n) { _name = n; }
	void	Tag(const std::string & t) { _tag = t; }
	void	Desc(const std::string & d) { _desc = d; }
	void	Width(const ushort w) { _width = w; }
	void	Length(const ushort l) { _length = l; }
	void	Lighting(const RoomLighting & r) { _idlighting = r; }


	void	AddItem(Item::pointer & i) { _items.push_back(i); }
	void	RemoveItem(entity_t id);

	void	AddCharacter(Character::pointer c) { _chars.push_back(c); }
	void	RemoveCharacter(entity_t id);
	Character::pointer GetCharacter(entity_t id);
	Character::pointer GetCharacter(std::string &c);

	void	AddPortal(Portal::pointer p) { _exits.push_back(p); }

	void	Lock() { _flags |= DOOR_LOCKED; }
	void	UnLock() { _flags &= ~DOOR_LOCKED; }

	const std::vector<Portal::pointer > & Exits() const { return _exits; }

	// See wiki for explanation of these
	void	AddDayChatter(const std::string &c) { _day_chats.push_back(c); }
	void	AddNightChatter(const std::string &c) { _night_chats.push_back(c); }

	// See wiki for explanation of these
	void	AddVirtualObject(const VirtualRoomObject & vro) { _vobj.push_back(vro); }
	void	AddVirtualObject(const std::string &i, const std::string &rt, const std::string & rw) {
		VirtualRoomObject vro(i,rt,rw);
		_vobj.push_back(vro);
	}

private:
	friend class odb::access;
	#pragma db id auto
	entity_t	_id;
	entity_t	_idregion;
#pragma db type("VARCHAR(64)")
	std::string	_name;
#pragma db type("VARCHAR(32)")
	std::string	_tag;
	std::string	_desc;
	std::string _light_desc;	// description at daytime or with lights
	std::string _dark_desc;		// description at night or no lights
	boost::posix_time::ptime		_last_reset;
	boost::posix_time::ptime		_next_reset;
	RoomType	_idroom_type;
	unsigned int _flags;
	ushort		_width;
	ushort		_length;
	RoomLighting	_idlighting;
	std::vector<boost::shared_ptr<Item> > _items;
	// TODO Consider using a std::set for character list below
	std::vector<Character::pointer> _chars;
	std::vector<Portal::pointer > _exits;
	entity_t	_creator;

	std::vector<std::string> _npczones;
	std::vector<VirtualRoomObject> _vobj;	// virtual objects (have desc and some
											// commands, but otherwise non-existent

//	uint8_t		_num_day_chats;	// these should be replaced by vector.len or .size
//	uint8_t		_num_night_chats;
	uint8_t		_pct_chat;	// % a chat will fire in the interval
	std::vector<std::string> _day_chats;
	std::vector<std::string> _night_chats;

	// TODO Add event and trigger lists

};



#endif /* _GOVT_ROOM_HPP_ */
